/**
 * 
 */
package com.carnation.qa.socketserver.proxy;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.carnation.mong.platform.domain.MOIData;
import com.carnation.mong.platform.service.DataService;
import com.carnation.qa.socketserver.common.util.MppContext;
import com.carnation.qa.socketserver.proxy.moi.ServiceFactory;

/**
 * @author Nick
 * 
 */
public class Builder {

	private final Log log = LogFactory.getLog(getClass());
	private final Object obj;
	/**
	 * 缩进字符串
	 */
	private final String tabs;
	private final String tabSeparator;
	private final String newLine = MppContext.getNewlineSeparator();

	/**
	 * @param obj
	 * @param tabs
	 * @param tabSeparator
	 */
	public Builder(Object obj, String tabs, String tabSeparator) {
		this.obj = obj;
		if (tabs == null) {
			this.tabs = "";
		} else {
			this.tabs = tabs;
		}
		this.tabSeparator = tabSeparator;
	}

	@SuppressWarnings("unchecked")
	public String toString() {
		StringBuilder sb = new StringBuilder();
		if (obj instanceof List) {
			List list = (List) obj;
			if (!list.isEmpty()) {
				sb.append(newLine + tabs + List.class.getSimpleName());
				for (int i = 0; i < list.size(); i++) {
					sb.append(newLine + tabs + buildTabs(1) + i);
					sb.append(new Builder(list.get(i), tabs + buildTabs(2),
							tabSeparator).toString());
				}
			}
		} else if (obj instanceof Map) {
			Map map = (Map) obj;
			if (!map.isEmpty()) {
				sb.append(newLine + tabs + Map.class.getSimpleName());
				Iterator it = map.keySet().iterator();
				while (it.hasNext()) {
					Object key = it.next();// 只支持key为String类型
					Object value = map.get(key);
					sb.append(newLine + tabs + buildTabs(1)
							+ buildStringValue(key.toString()));
					if (isBasicType(value)) {
						sb.append(buildTabs(1) + getBasicTypeValue(value));
					} else {
						sb.append(new Builder(value, tabs + buildTabs(2),
								tabSeparator).toString());
					}
				}
			}
		} else if (isBasicType(obj)) {
			sb.append(newLine + tabs + getBasicTypeValue(obj));
		} else {
			sb.append(newLine + tabs + obj.getClass().getSimpleName());
			appendMOIDataPath(obj, sb);
			Method[] methods = obj.getClass().getMethods();
			for (Method m : methods) {
				if (m.getParameterTypes().length == 0) {
					if (isSystemMethod(m)) {
						continue;
					}
					sb.append(newLine + tabs + buildTabs(1) + m.getName());
					try {
						Object value = m.invoke(obj, new Object[] {});
						if (isBasicType(value)) {
							sb.append(buildTabs(1) + getBasicTypeValue(value));
						} else {
							sb.append(new Builder(value, tabs + buildTabs(2),
									tabSeparator).toString());
						}
					} catch (Exception e) {
						if (log.isErrorEnabled()) {
							log.error(e.getMessage(), e);
						}
					}
				}

			}
		}
		return sb.toString();
	}

	private String getBasicTypeValue(Object o) {
		if (o == null) {
			return buildNullValue();
		} else if (isLong(o)) {
			return buildLongValue((Long) o);
		} else if (isString(o)) {
			return buildStringValue(o.toString());
		} else if (isDate(o)) {
			return buildDateValue((Date) o);
		} else {
			return o.toString();
		}
	}

	private boolean isBasicType(Object o) {
		boolean value = isNull(o) || isString(o) || (o instanceof Number)
				|| (o instanceof Boolean) || isDate(o);
		return value;
	}

	private boolean isNull(Object o) {
		return o == null;
	}

	private boolean isString(Object o) {
		return (o instanceof String) || (o instanceof Character);
	}

	private boolean isDate(Object o) {
		return o instanceof Date;
	}

	private boolean isLong(Object o) {
		return o instanceof Long;
	}

	private boolean isSystemMethod(Method m) {
		String declaringClassName = (m.getDeclaringClass().getName());
		return (declaringClassName.equals(Class.class.getName())
				|| declaringClassName.equals(Object.class.getName()) || m
				.getName().equals("toString"));
	}

	private String buildTabs(int times) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < times; i++) {
			sb.append(tabSeparator);
		}
		return sb.toString();
	}

	private String buildNullValue() {
		return "null";
	}

	private String buildStringValue(String str) {
		return "\"" + str + "\"";
	}

	private String buildDateValue(Date date) {
		return new SimpleDateFormat(MppContext.getDateFormat()).format(date);
	}

	private String buildLongValue(Long l) {
		return l.toString() + "L";
	}

	/**
	 * 若是MOIData对象，增加 getPath “x/x/x” 内容
	 * 
	 * @param obj
	 * @param sb
	 */
	private void appendMOIDataPath(Object obj, StringBuilder sb) {
		if (obj instanceof MOIData) {
			MOIData d = (MOIData) obj;
			if (d.getId() != null) {
				try {
					String path = ServiceFactory.getService(DataService.class)
							.getPath(d);
					sb.append(newLine + tabs + buildTabs(1) + "getPath");
					sb.append(buildTabs(1) + getBasicTypeValue(path));
				} catch (Exception e) {
					if (log.isWarnEnabled()) {
						log.warn(e.getMessage(), e);
					}
				}
			}
		}
	}
}
